/***************************************************************************************************************************************
 * Copyright (C) 2001-2012 LearnLift USA																	*
 * Contact: Learnlift USA, 12 Greenway Plaza, Suite 1510, Houston, Texas 77046, support@memorylifter.com					*
 *																								*
 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License	*
 * as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.			*
 *																								*
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty	*
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.	*
 *																								*
 * You should have received a copy of the GNU Lesser General Public License along with this library; if not,					*
 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA					*
 ***************************************************************************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
// The following code was generated by Microsoft Visual Studio 2005.
// The test owner should check each test for validity.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MLifter.BusinessLayer;
using MLifter.DAL;
using MLifter.DAL.Interfaces;
using System.Diagnostics;
namespace MLifterTest
{
	/// <summary>
	///This is a test class for MLifter.BusinessLayer.LearningModulesIndex and is intended
	///to contain all MLifter.BusinessLayer.LearningModulesIndex Unit Tests
	///</summary>
	[TestClass()]
	public class LearningModulesIndexTest
	{
		private TestContext testContextInstance;
		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		private string testUncPath = string.Empty;
		# region odxContent
		string odxContent = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n" +
							"<dictionary>\n" +
							"  <general>\n" +
							"    <version>267</version>\n" +
							"    <author>OMICRON</author>\n" +
							"    <Description>Demodescription</Description>\n" +
							"    <category id=\"1\">1</category>\n" +
							"  </general>\n" +
							"  <stats id=\"0\">\n" +
							"    <start>2000-01-01T12:00:00+01:00</start>\n" +
							"    <end>2000-01-01T12:10:00+01:00</end>\n" +
							"    <right>6</right>\n" +
							"    <wrong>4</wrong>\n" +
							"    <boxes id=\"0\">0</boxes>\n" +
							"    <boxes id=\"1\">1</boxes>\n" +
							"    <boxes id=\"2\">2</boxes>\n" +
							"    <boxes id=\"3\">3</boxes>\n" +
							"    <boxes id=\"4\">4</boxes>\n" +
							"    <boxes id=\"5\">5</boxes>\n" +
							"    <boxes id=\"6\">6</boxes>\n" +
							"    <boxes id=\"7\">7</boxes>\n" +
							"    <boxes id=\"8\">8</boxes>\n" +
							"    <boxes id=\"9\">9</boxes>\n" +
							"  </stats>\n" +
							"  <user>\n" +
							"    <score>1</score>\n" +
							"    <hiscore>22</hiscore>\n" +
							"    <querydir>0</querydir>\n" +
							"    <querytype bitmask=\"1\">1</querytype>\n" +
							"    <queryoptions bitmask=\"2464\">9316</queryoptions>\n" +
							"    <gradesynonyms>2</gradesynonyms>\n" +
							"    <emptymessage>true</emptymessage>\n" +
							"    <stripchars>.!?;,</stripchars>\n" +
							"    <gradetyping>1</gradetyping>\n" +
							"    <end-time bitmask=\"A\">10</end-time>\n" +
							"    <end-rights bitmask=\"A\">10</end-rights>\n" +
							"    <end-cards bitmask=\"A\">10</end-cards>\n" +
							"    <snooze-low bitmask=\"37\">55</snooze-low>\n" +
							"    <snooze-high bitmask=\"37\">55</snooze-high>\n" +
							"    <usedicstyle>true</usedicstyle>\n" +
							"    <boxsize id=\"1\">10</boxsize>\n" +
							"    <boxsize id=\"2\">20</boxsize>\n" +
							"    <boxsize id=\"3\">50</boxsize>\n" +
							"    <boxsize id=\"4\">100</boxsize>\n" +
							"    <boxsize id=\"5\">250</boxsize>\n" +
							"    <boxsize id=\"6\">500</boxsize>\n" +
							"    <boxsize id=\"7\">1000</boxsize>\n" +
							"    <boxsize id=\"8\">2000</boxsize>\n" +
							"    <boxsize id=\"9\">4000</boxsize>\n" +
							"    <querychapter id=\"0\">0</querychapter>\n" +
							"  </user>\n" +
							"  <chapter id=\"0\">\n" +
							"    <title>Chapter 1</title>\n" +
							"    <Description>Default chapter</Description>\n" +
							"  </chapter>\n" +
							"  <card id=\"0\">\n" +
							"    <box>0</box>\n" +
							"    <chapter>0</chapter>\n" +
							"    <question>Question</question>\n" +
							"	<questionexample>Question example</questionexample>\n" +
							"    <answer>Answer</answer>\n" +
							"    <answerexample>Answer example</answerexample>\n" +
							"    <timestamp>2008-04-07T10:49:44.780352</timestamp>\n" +
							"  </card>\n" +
							"</dictionary>";
		# endregion

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//Use TestInitialize to run code before running each test
		//
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}

		//
		//Use TestCleanup to run code after each test has run
		//
		[TestCleanup()]
		public void MyTestCleanup()
		{
			try
			{
				if (Directory.Exists(testUncPath))
					Directory.Delete(testUncPath, true);
			}
			catch
			{

			}
		}

		#endregion

		private int scannedModules = 0;
		void lmIndex_LearningModuleUpdated(object sender, LearningModuleUpdatedEventArgs e)
		{
			if (e.Entry.DisplayName.StartsWith("ODX-"))
				scannedModules++;
		}

		[TestMethod(), Ignore]
		public void LMIndexPasswordCacheTest()
		{
			//
			// ODX isn't supported anymore
			//

			# region odxContent
			string odxContent = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n" +
								"<dictionary>\n" +
								"  <general>\n" +
								"    <version>267</version>\n" +
								"    <author>OMICRON</author>\n" +
								"    <Description>Demodescription</Description>\n" +
								"    <category id=\"1\">1</category>\n" +
								"  </general>\n" +
								"  <stats id=\"0\">\n" +
								"    <start>2000-01-01T12:00:00+01:00</start>\n" +
								"    <end>2000-01-01T12:10:00+01:00</end>\n" +
								"    <right>6</right>\n" +
								"    <wrong>4</wrong>\n" +
								"    <boxes id=\"0\">0</boxes>\n" +
								"    <boxes id=\"1\">1</boxes>\n" +
								"    <boxes id=\"2\">2</boxes>\n" +
								"    <boxes id=\"3\">3</boxes>\n" +
								"    <boxes id=\"4\">4</boxes>\n" +
								"    <boxes id=\"5\">5</boxes>\n" +
								"    <boxes id=\"6\">6</boxes>\n" +
								"    <boxes id=\"7\">7</boxes>\n" +
								"    <boxes id=\"8\">8</boxes>\n" +
								"    <boxes id=\"9\">9</boxes>\n" +
								"  </stats>\n" +
								"  <user>\n" +
								"    <score>1</score>\n" +
								"    <hiscore>22</hiscore>\n" +
								"    <querydir>0</querydir>\n" +
								"    <querytype bitmask=\"1\">1</querytype>\n" +
								"    <queryoptions bitmask=\"2464\">9316</queryoptions>\n" +
								"    <gradesynonyms>2</gradesynonyms>\n" +
								"    <emptymessage>true</emptymessage>\n" +
								"    <stripchars>.!?;,</stripchars>\n" +
								"    <gradetyping>1</gradetyping>\n" +
								"    <end-time bitmask=\"A\">10</end-time>\n" +
								"    <end-rights bitmask=\"A\">10</end-rights>\n" +
								"    <end-cards bitmask=\"A\">10</end-cards>\n" +
								"    <snooze-low bitmask=\"37\">55</snooze-low>\n" +
								"    <snooze-high bitmask=\"37\">55</snooze-high>\n" +
								"    <usedicstyle>true</usedicstyle>\n" +
								"    <boxsize id=\"1\">10</boxsize>\n" +
								"    <boxsize id=\"2\">20</boxsize>\n" +
								"    <boxsize id=\"3\">50</boxsize>\n" +
								"    <boxsize id=\"4\">100</boxsize>\n" +
								"    <boxsize id=\"5\">250</boxsize>\n" +
								"    <boxsize id=\"6\">500</boxsize>\n" +
								"    <boxsize id=\"7\">1000</boxsize>\n" +
								"    <boxsize id=\"8\">2000</boxsize>\n" +
								"    <boxsize id=\"9\">4000</boxsize>\n" +
								"    <querychapter id=\"0\">0</querychapter>\n" +
								"  </user>\n" +
								"  <chapter id=\"0\">\n" +
								"    <title>Chapter 1</title>\n" +
								"    <Description>Default chapter</Description>\n" +
								"  </chapter>\n" +
								"  <card id=\"0\">\n" +
								"    <box>0</box>\n" +
								"    <chapter>0</chapter>\n" +
								"    <question>Question</question>\n" +
								"	<questionexample>Question example</questionexample>\n" +
								"    <answer>Answer</answer>\n" +
								"    <answerexample>Answer example</answerexample>\n" +
								"    <timestamp>2008-04-07T10:49:44.780352</timestamp>\n" +
								"  </card>\n" +
								"</dictionary>";
			# endregion

			string demopath = Path.Combine(Path.GetTempPath(), "LMIndexTempFolder");

			try
			{
				Directory.CreateDirectory(demopath);

				UncConnectionStringBuilder uncConnection = new UncConnectionStringBuilder(demopath);
				uncConnection.Name = "Demo";
				XmlSerializer uncSerializer = new XmlSerializer(typeof(UncConnectionStringBuilder));
				using (Stream uncStream = File.Create(Path.Combine(demopath, "demo.mlcfg")))
				{
					XmlWriterSettings settings = new XmlWriterSettings();
					settings.Indent = true;
					XmlWriter writer = XmlTextWriter.Create(uncStream, settings);
					writer.WriteStartElement("Configuration");
					writer.WriteStartElement("Connections");
					uncSerializer.Serialize(writer, uncConnection);
					writer.WriteEndElement();
					writer.WriteEndElement();

					writer.Close();
					uncStream.Close();
				}

				File.WriteAllText(Path.Combine(demopath, "LM.odx"), odxContent, System.Text.Encoding.Unicode);

				LearningModulesIndex lmIndex = new LearningModulesIndex(string.Empty, demopath,
					(GetLoginInformation)delegate(UserStruct u, ConnectionStringStruct c) { return new UserStruct(); },
					(DataAccessErrorDelegate)delegate(object sender, Exception exp) { return; }, string.Empty);

				FolderIndexEntry folder = lmIndex.GetFolderOfConnection(LearningModulesIndex.ConnectionsHandler.ConnectionStrings[0]);
				folder.BeginLoading();
				while (folder.GetContainingEntries(true).Count < 1) Thread.Sleep(10);

				ConnectionStringStruct css = lmIndex.LearningModules[0].ConnectionString;
				css.ProtectedLm = true;
				css.Password = "123";
				lmIndex.LearningModules[0].ConnectionString = css;

				lmIndex.DumpIndexCache(lmIndex.CacheFile);

				LearningModulesIndex lmIndex2 = new LearningModulesIndex(string.Empty, demopath,
					(GetLoginInformation)delegate(UserStruct u, ConnectionStringStruct c) { return new UserStruct(); },
					(DataAccessErrorDelegate)delegate(object sender, Exception exp) { return; }, string.Empty);

				folder = lmIndex2.GetFolderOfConnection(LearningModulesIndex.ConnectionsHandler.ConnectionStrings[0]);
				folder.BeginLoading();
				while (folder.GetContainingEntries(true).Count < 1) Thread.Sleep(10);

				Assert.IsTrue((folder.GetContainingEntries(true)[0] as LearningModulesIndexEntry).ConnectionString.ProtectedLm, "Protected Flag not saved/restored!");
				Assert.AreEqual<string>(string.Empty, (folder.GetContainingEntries(true)[0] as LearningModulesIndexEntry).ConnectionString.Password, "Password not cleared!");
			}
			finally
			{
				Directory.Delete(demopath, true);
			}
		}

		/// <summary>
		/// IIndexEntry Tests... (Folder and LMs)
		/// </summary>
		/// <remarks>Documented by Dev08, 2009-03-17</remarks>
		[TestMethod()]
		public void LMIndexTest2()
		{
			#region Step 1: Create the UNC path and fill it with 5 ODX-LMs
			testUncPath = Path.Combine(Path.GetTempPath(), "TestUncPath");

			this.MyTestCleanup();
			if (Directory.Exists(testUncPath))
				throw new Exception("Can not delete test-UNC-Path...");

			Directory.CreateDirectory(testUncPath);

			int numberOfModules = 5;
			for (int i = 0; i < numberOfModules; i++)
				File.WriteAllText(Path.Combine(testUncPath, string.Format("ODX-{0}.odx", (i + 1))), odxContent, System.Text.Encoding.Unicode);

			int numberOfFolders = 5;
			for (int i = 0; i < numberOfFolders; i++)
				Directory.CreateDirectory(Path.Combine(testUncPath, string.Format("Folder-{0}", (i + 1))));

			#endregion

			#region Step 2: Create two ML-CFG files and copy them into the UNC path

			UncConnectionStringBuilder uncConnection = new UncConnectionStringBuilder(testUncPath, true, false);
			uncConnection.Name = "Demo";
			XmlSerializer uncSerializer = new XmlSerializer(typeof(UncConnectionStringBuilder));
			using (Stream uncStream = File.Create(Path.Combine(testUncPath, "demo.mlcfg")))
			{
				XmlWriterSettings settings = new XmlWriterSettings();
				settings.Indent = true;
				XmlWriter writer = XmlTextWriter.Create(uncStream, settings);
				writer.WriteStartElement("Configuration");
				writer.WriteStartElement("Connections");
				uncSerializer.Serialize(writer, uncConnection);
				writer.WriteEndElement();
				writer.WriteEndElement();

				writer.Close();
				uncStream.Close();
			}

			//UncConnectionStringBuilder uncConnection2 = new UncConnectionStringBuilder(testUncPath + "_somethingElse", false);
			//uncConnection2.Name = "Demo 2";
			//XmlSerializer uncSerializer2 = new XmlSerializer(typeof(UncConnectionStringBuilder));
			//using (Stream uncStream2 = File.Create(Path.Combine(testUncPath, "demo2.mlcfg")))
			//{
			//    XmlWriterSettings settings = new XmlWriterSettings();
			//    settings.Indent = true;
			//    XmlWriter writer = XmlTextWriter.Create(uncStream2, settings);
			//    writer.WriteStartElement("Configuration");
			//    writer.WriteStartElement("Connections");
			//    uncSerializer2.Serialize(writer, uncConnection2);
			//    writer.WriteEndElement();
			//    writer.WriteEndElement();

			//    writer.Close();
			//    uncStream2.Close();
			//}

			#endregion

			#region Step 3: Create a LearningModuleIndex and copy init it

			LearningModulesIndex lmIndex = new LearningModulesIndex(testUncPath, string.Empty,
					(GetLoginInformation)delegate(UserStruct u, ConnectionStringStruct c) { return new UserStruct(); },
					(DataAccessErrorDelegate)delegate(object sender, Exception exp) { return; }, string.Empty);

			Assert.AreEqual<int>(1, LearningModulesIndex.ConnectionsHandler.ConnectionStrings.FindAll(c => !(c is UncConnectionStringBuilder) || !(c as UncConnectionStringBuilder).IsOnStick).Count, "Connections count wrong!");

			#endregion

			#region Step 4: Scanning Modules:

			scannedModules = 0;
			lmIndex.LearningModuleUpdated += new LearningModuleUpdatedEventHandler(lmIndex_LearningModuleUpdated);
			lmIndex.BeginLearningModulesScan();

			Trace.Write("Scanning modules...");
			while (scannedModules < numberOfModules)
			{
				Trace.Write(".");
				Thread.Sleep(100);
			}
			Trace.WriteLine(" Finish!");

			#endregion

			#region Step 5: Checking the entries

			Assert.AreEqual<int>(numberOfModules, lmIndex.LearningModules.FindAll(m => m.DisplayName.StartsWith("ODX-")).Count, "LM count is wrong!");

			int counter = 0;
			foreach (LearningModulesIndexEntry entry in lmIndex.LearningModules.FindAll(m => m.DisplayName.StartsWith("ODX-")))
			{
				Assert.AreEqual<string>("OMICRON", entry.Author, "Author is not correct");
				Assert.AreEqual<int>(1, entry.Category.Id, "Category read wrong!");

				Assert.AreEqual<DatabaseType>(DatabaseType.Unc, entry.Connection.ConnectionType, "Connection.Type is wrong");
				Assert.AreEqual<string>(testUncPath, entry.Connection.ConnectionString, "Connection.String is wrong");
				Assert.IsTrue(entry.Connection.IsDefault, "Connection.IsDefault is wrong");
				Assert.AreEqual<string>("Demo", entry.Connection.Name, "Connection.Name is wrong");
				Assert.AreEqual<string>("Demo", entry.ConnectionName, "ConnectionName is wrong");
				Assert.AreEqual<string>(Path.Combine(testUncPath, string.Format("ODX-{0}.odx", (counter + 1))), entry.ConnectionString.ConnectionString, "ConnectionString is wrong");

				Assert.AreEqual<int>(1, entry.Count, "Card count is wrong");
				//Assert.AreEqual<string>("Demodescription", entry.Description, "Description is wrong");
				Assert.IsNotNull(entry.Dictionary, "Dictionary is null");
				Assert.AreEqual<string>(string.Format("ODX-{0}", (counter + 1)), entry.DisplayName, "DisplayName is wrong");
				Assert.AreEqual<string>("Demo", entry.Group.Header, "Group is wrong");
				Assert.IsTrue(entry.IsAccessible, "IsAccessible is wrong");
				Assert.IsFalse(entry.IsFromCache, "IsFromCache is wrong");
				Assert.IsTrue(entry.IsVerified, "IsVerified is wrong");

				Assert.AreEqual<DateTime>(new DateTime(2000, 1, 1, 12, 0, 0), entry.LastTimeLearned, "LastTimeLearned is wrong!");
				Assert.IsNotNull(entry.Preview, "Preview is null");

				Assert.AreEqual<int>(10, entry.Statistics.CardsAsked, "Cards asked read wrong!");
				Assert.AreEqual<double>(1, entry.Statistics.CardsPerMinute, "Cards per minute calculated wrong!");
				Assert.AreEqual<DateTime>(new DateTime(2000, 1, 1, 12, 10, 0), entry.Statistics.LastEndTime, "Last end time read wrong!");
				Assert.AreEqual<TimeSpan>(new TimeSpan(0, 10, 0), entry.Statistics.LastSessionTime, "Last session time read wrong!");
				Assert.AreEqual<DateTime>(new DateTime(2000, 1, 1, 12, 0, 0), entry.Statistics.LastStartTime, "Last start time read wrong!");
				Assert.AreEqual<double>(60, entry.Statistics.Ratio, "Ratio calculated wrong!");
				Assert.AreEqual<int>(6, entry.Statistics.Right, "Right read wrong!");
				Assert.AreEqual<TimeSpan>(new TimeSpan(0, 1, 0), entry.Statistics.TimePerCard, "Time per card calculated wrong!");
				Assert.AreEqual<int>(4, entry.Statistics.Wrong, "Wrong read wrong!");

				Assert.AreEqual<LearningModuleType>(LearningModuleType.Local, entry.Type, "Type is wrong!");

				++counter;
			}

			#endregion

			#region Step 7: Checking the entries

			counter = 0;
			bool rootNodeFound = false;
			foreach (FolderIndexEntry entry in lmIndex.Folders.FindAll(f => !(f.Connection is UncConnectionStringBuilder) || !(f.Connection as UncConnectionStringBuilder).IsOnStick))
			{
				Assert.AreEqual<DatabaseType>(DatabaseType.Unc, entry.Connection.ConnectionType, "Connection.Type is wrong");
				Assert.AreEqual<string>(testUncPath, entry.Connection.ConnectionString, "Connection.String is wrong");
				Assert.IsTrue(entry.Connection.IsDefault, "Connection.IsDefault is wrong");
				Assert.AreEqual<string>("Demo", entry.Connection.Name, "Connection.Name is wrong");

				if (entry.IsRootNode)
				{
					if (rootNodeFound)
						throw new Exception("More than one root node found");

					Assert.AreEqual<int>(5, entry.Count, "LM count is wrong");
					Assert.AreEqual<string>("Demo", entry.DisplayName, "DisplayName is wrong");
					Assert.AreEqual<string>(testUncPath, entry.Path, "Path is wrong");
					rootNodeFound = true;
				}
				else
				{
					Assert.AreEqual<int>(0, entry.Count, "LM count is wrong");
					Assert.AreEqual<string>(string.Format("Folder-{0}", (counter + 1)), entry.DisplayName, "DisplayName is wrong");
					Assert.AreEqual<string>(Path.Combine(testUncPath, string.Format("Folder-{0}", (counter + 1))), entry.Path, "Path is wrong");
					++counter;
				}
				Assert.IsFalse(entry.IsFromCache, "IsFromCache is wrong");
				Assert.IsFalse(entry.IsLoading, "IsLoading is wrong");
			}

			#endregion
		}
	}
}
